using Acornima.Ast;
using Jint;
using Jint.Runtime;
using Jint.Runtime.Debugger;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using T.FAS.Runtime.Base.Common;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Expression.Entity;
using T.FAS.Runtime.Expression.SPI;
using T.ServiceComponent.Kernel.Service;
using T.ServiceComponent.Log.Client;
using T.ServiceComponent.Log.SPI;

namespace T.FAS.Runtime.Expression.Service
{
    public class ExprService
    {
        public static List<DebugLog> debugLog = null;
        private static readonly object lockobj = new object();
        private static ExprService instance = null;
        private static List<string> executors = null;
        private static string requestID = null;
        private static string hostName = string.Empty;
        private ExprService()
        {
        }
        public static ExprService GetInstance
        {
            get
            {
                if (instance == null)
                {
                    lock (lockobj)
                    {
                        if (instance == null)
                        {
                            executors = new List<string>();
                            instance = new ExprService();
                        }
                    }
                }

                return instance;
            }
        }
        /// <summary>
        /// 主机名
        /// </summary>
        private string HostName
        {
            get
            {
                if (string.IsNullOrEmpty(hostName))
                    hostName = Dns.GetHostName();
                return hostName;
            }
        }
        #region 公共方法
        /// <summary>
        /// 本周一
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        private DateTime GetFisrtDayOfTheWeek(DateTime dt)
        {
            int dayOfWeek = -1 * (int)dt.DayOfWeek;
            if (dayOfWeek == 0)
                return dt.AddDays(-6);
            return dt.AddDays(dayOfWeek + 1);
        }
        /// <summary>
        /// 本周日
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        private DateTime GetLastDayOfTheWeek(DateTime dt)
        {
            int dayOfWeek = -1 * (int)dt.DayOfWeek;
            if (dayOfWeek == 0)
                return dt;
            return dt.AddDays(dayOfWeek + 7);
        }
        /// <summary>
        /// Group处理@
        /// </summary>
        /// <returns></returns>
        public void TransformGroup(Group group, string userId = "", string userName = "")
        {
            if (group?.Filters?.Count > 0)
            {
                foreach (var item in group.Filters)
                {
                    if (item is Filter filter)
                    {
                        for (int i = 0; i < filter.Value.Count; i++)
                        {
                            if (filter.ValueName == "@我")
                            {
                                filter.Condition = "in";
                            }
                            if(filter.Condition == "isblank")
                            {
                                filter.Condition = "=";
                                filter.Value = null;
                                continue;
                            }
                            var js = filter.Value[i];
                            if (js?.StartsWith("@") == true)
                            {
                                char[] chars = { '+', '-' };
                                var statements = js.Split(chars);
                                if (statements.Length == 0 || statements.Length > 2)
                                    throw new FasException(ExprExceptionCode.ErrorExpr, "不正确的查询条件" + js);
                                DateTime dt = DateTime.Now;
                                switch (statements[0])
                                {
                                    case "@我":
                                        if (string.IsNullOrEmpty(userId))
                                        {
                                            filter.Value = new List<string> { UserUtil.GetCurrentUserID(), UserUtil.GetCurrentUserName() };
                                        }
                                        else
                                        {
                                            filter.Value = new List<string> { userId, userName };
                                        }
                                        continue;
                                    case "@今天":
                                    case "@今日":
                                    case "@今日初":
                                    case "@今日末":
                                        break;
                                    case "@昨日":
                                        dt = dt.AddDays(-1);
                                        break;
                                    case "@本周":
                                        filter.Value = new List<string> { GetFisrtDayOfTheWeek(dt).ToString("yyyy-MM-dd 00:00:00"), GetLastDayOfTheWeek(dt).ToString("yyyy-MM-dd 23:59:59") };
                                        continue;
                                    case "@本周一":
                                        dt = GetFisrtDayOfTheWeek(dt);
                                        break;
                                    case "@本周日":
                                        dt = GetLastDayOfTheWeek(dt);
                                        break;
                                    case "@上周":
                                        filter.Value = new List<string> { GetFisrtDayOfTheWeek(dt).AddDays(-7).ToString("yyyy-MM-dd 00:00:00"), GetLastDayOfTheWeek(dt).AddDays(-7).ToString("yyyy-MM-dd 23:59:59") };
                                        continue;
                                    case "@上周一":
                                        dt = GetFisrtDayOfTheWeek(dt).AddDays(-7);
                                        break;
                                    case "@上周日":
                                        dt = GetLastDayOfTheWeek(dt).AddDays(-7);
                                        break;
                                    case "@本月":
                                        filter.Value = new List<string> { new DateTime(dt.Year, dt.Month, 1).ToString("yyyy-MM-dd 00:00:00"), new DateTime(dt.Year, dt.Month, 1).AddMonths(1).AddDays(-1).ToString("yyyy-MM-dd 23:59:59") };
                                        continue;
                                    case "@本月初":
                                        dt = new DateTime(dt.Year, dt.Month, 1);
                                        break;
                                    case "@本月末":
                                        dt = new DateTime(dt.Year, dt.Month, 1).AddMonths(1).AddDays(-1);
                                        break;
                                    case "@上月":
                                        filter.Value = new List<string> { new DateTime(dt.Year, dt.Month, 1).AddMonths(-1).ToString("yyyy-MM-dd 00:00:00"), new DateTime(dt.Year, dt.Month, 1).AddDays(-1).ToString("yyyy-MM-dd 23:59:59") };
                                        continue;
                                    case "@上月初":
                                        dt = new DateTime(dt.Year, dt.Month, 1).AddMonths(-1);
                                        break;
                                    case "@上月末":
                                        dt = new DateTime(dt.Year, dt.Month, 1).AddDays(-1);
                                        break;
                                    case "@本年":
                                    case "@今年":
                                        filter.Value = new List<string> { dt.Year + "-01-01 00:00:00", new DateTime(dt.Year, 12, 31).ToString("yyyy-MM-dd 23:59:59") };
                                        continue;
                                    case "@今年初":
                                        dt = new DateTime(dt.Year, 1, 1);
                                        break;
                                    case "@今年末":
                                        dt = new DateTime(dt.Year, 12, 31);
                                        break;
                                    case "@上年":
                                    case "@去年":
                                        filter.Value = new List<string> { dt.Year - 1 + "-01-01 00:00:00", new DateTime(dt.Year - 1, 12, 31).ToString("yyyy-MM-dd 23:59:59") };
                                        continue;
                                    case "@上年初":
                                        dt = new DateTime(dt.Year, 1, 1);
                                        break;
                                    case "@上年末":
                                        dt = new DateTime(dt.Year, 1, 1);
                                        break;
                                    default:
                                        throw new ArgumentException("不正确的查询条件" + js);
                                }
                                if (statements.Length == 1)
                                    filter.Value[i] = dt.ToString("yyyy-MM-dd");
                                else
                                {
                                    int days;
                                    bool isTrans = int.TryParse(statements[1], out days);
                                    if (!isTrans)
                                        throw new ArgumentException("不正确的查询条件" + js);
                                    if (js.Contains("+"))
                                        filter.Value[i] = dt.AddDays(days).ToString("yyyy-MM-dd");
                                    else
                                        filter.Value[i] = dt.AddDays(-days).ToString("yyyy-MM-dd");
                                }
                            }
                        }
                    }
                    else if (item is Group childGroup)
                    {
                        TransformGroup(childGroup, userId, userName);
                    }
                }
            }
        }
        #endregion
        /// <summary>
        /// 初始化引擎
        /// </summary>
        /// <param name="inputParam"></param>
        /// <returns></returns>
        private Engine InitEngine(Dictionary<string, object> inputParam)
        {
            Options options = new Options();
            options.AllowClr();
            Engine engine = new Engine(options);
            var hashTable = T.ServiceComponent.Session.Service.AppContext.Current.Session as Hashtable;
            var dic = new Dictionary<string, string>();
            if (hashTable != null)
            {
                var listKeys = new List<string>();
                foreach (var item in hashTable.Keys)
                {
                    if (item != null)
                    {
                        var key = Convert.ToString(item);
                        listKeys.Add(key);
                    }
                }

                var index = 0;
                foreach (var val in hashTable.Values)
                {
                    dic[listKeys[index]] = Convert.ToString(val);
                    index++;
                }

                engine.SetValue("Session", dic);
            }
            else
            {
                dic["UserId"] = "T";
                dic["UserName"] = "T";
                engine.SetValue("Session", dic);
            }

            Dictionary<string, IDynamicActionAdapter> dynamicActionAdapters = AdapterCache.GetInstance().GetIDynamicActionAdapters();
            foreach (var item in dynamicActionAdapters)
            {
                engine.SetValue(item.Key, item.Value);
            }
            foreach (var item in inputParam)
            {
                engine.SetValue(item.Key, inputParam[item.Key]);
            }

            return engine;
        }

        #region 表达式引擎执行
        /// <summary>
        /// 执行JS脚本 带FASContext参数
        /// </summary>
        /// <returns></returns>
        public ExprResult Execute(string jsString, FASContext fASContext, Dictionary<string, object> inputParam)
        {
            if (inputParam == null)
                inputParam = new Dictionary<string, object>();
            inputParam["FASContext"] = fASContext;
            return JSExecute(jsString, inputParam);
        }
        /// <summary>
        /// 执行JS脚本
        /// </summary>
        /// <returns></returns>
        public ExprResult JSExecute(string jsString, Dictionary<string, object> inputParam)
        {
            ExprResult exprResult = new ExprResult();
            Exception e = null;
            var start = DateTime.Now;
            string rpcID = RpcContext.Current.RpcID;
            RpcContext.Current.SetRpcID(rpcID);
            string reportRpcID = RpcContext.Current.RpcID;
            RpcContext.Current.SetRpcID(reportRpcID);
            SysActionLog dataChangeLog = new SysActionLog
            {
                ServerIP = HostName,
                CreateTime = DateTime.Now,
                UserID = Base.Common.UserUtil.GetCurrentUserID(),
                ModuleCode = "Expr",
                AppCode = "FAS",
                Action = "FAS-Expr",
                Context = jsString,
                Ext1 = "入参：" + JsonConvert.SerializeObject(inputParam),
                Ext2 = reportRpcID,
            };
            try
            {
                Engine engine = InitEngine(inputParam);
                object result = engine.Evaluate(jsString)?.ToObject();
                exprResult.State = ResultState.Success;
                exprResult.Result = result;
                dataChangeLog.Result = "Success";
                return exprResult;
            }
            catch (JavaScriptException ex)
            {
                e = ex;
                exprResult.RowNum = ex.Location.Start.Line;
                exprResult.State = ResultState.Fail;
                exprResult.ErrMsg = e.Message;
                ExpressionMonitor.RootCaseReport(start, reportRpcID, e);
                dataChangeLog.Result = "Fail";
                dataChangeLog.Ext3 = "错误信息：" + e.Message;
                dataChangeLog.Ext4 = "错误行号：" + ex.Location.Start.Line.ToString();
                dataChangeLog.Ext5 = "错误列号：" + ex.Location.Start.Column.ToString();
                Base.Common.LogUtil.Log(e.ToString(), "ExprError");
                return exprResult;
            }
            catch (Exception ex)
            {
                e = ex;
                exprResult.State = ResultState.Fail;
                exprResult.ErrMsg = e.Message;
                ExpressionMonitor.RootCaseReport(start, reportRpcID, e);
                dataChangeLog.Result = "Fail";
                dataChangeLog.Ext3 = "错误信息：" + e.Message;
                Base.Common.LogUtil.Log(e.ToString(), "ExprError");
                return exprResult;
            }
            finally
            {
                ExpressionMonitor.Trace(start, reportRpcID, e);
                ExpressionMonitor.MointorExecuteTotal();
                if (e == null)
                {
                    ExpressionMonitor.MointorExecuteSuccessTPS();
                    ExpressionMonitor.MointorExecuteSuccessDuration((DateTime.Now - start).TotalMilliseconds);
                }
                else
                {
                    using (var client = new LogLocalClient())
                    {
                        client.SendLogs(new ILog[] { dataChangeLog });
                    }
                    ExpressionMonitor.MointorExecuteFailTPS();
                }

                RpcContext.Current.ResetRpcID(rpcID);
            }
        }
        /// <summary>
        /// 执行JS脚本不上报异常
        /// </summary>
        /// <returns></returns>
        public ExprResult JSExecuteNotReport(string jsString, Dictionary<string, object> inputParam)
        {
            ExprResult exprResult = new ExprResult();
            Exception e = null;
            var start = DateTime.Now;
            string rpcID = RpcContext.Current.RpcID;
            RpcContext.Current.SetRpcID(rpcID);
            string reportRpcID = RpcContext.Current.RpcID;
            RpcContext.Current.SetRpcID(reportRpcID);
            SysActionLog dataChangeLog = new SysActionLog
            {
                ServerIP = HostName,
                CreateTime = DateTime.Now,
                UserID = Base.Common.UserUtil.GetCurrentUserID(),
                ModuleCode = "Expr",
                AppCode = "FAS",
                Action = "FAS-Expr",
                Context = jsString,
                Ext1 = "入参：" + JsonConvert.SerializeObject(inputParam),
                Ext2 = reportRpcID,
            };
            try
            {
                Engine engine = InitEngine(inputParam);
                object result = engine.Evaluate(jsString)?.ToObject();
                exprResult.State = ResultState.Success;
                exprResult.Result = result;
                dataChangeLog.Result = "Success";
                return exprResult;
            }
            catch (JavaScriptException ex)
            {
                e = ex;
                exprResult.RowNum = ex.Location.Start.Line;
                exprResult.State = ResultState.Fail;
                exprResult.ErrMsg = e.Message;
                dataChangeLog.Result = "Fail";
                dataChangeLog.Ext3 = "错误信息：" + e.Message;
                dataChangeLog.Ext4 = "错误行号：" + ex.Location.Start.Line.ToString();
                dataChangeLog.Ext5 = "错误列号：" + ex.Location.Start.Column.ToString();
                Base.Common.LogUtil.Log(e.ToString(), "ExprError");
                return exprResult;
            }
            catch (Exception ex)
            {
                e = ex;
                exprResult.State = ResultState.Fail;
                exprResult.ErrMsg = e.Message;
                dataChangeLog.Result = "Fail";
                dataChangeLog.Ext3 = "错误信息：" + e.Message;
                Base.Common.LogUtil.Log(e.ToString(), "ExprError");
                return exprResult;
            }
            finally
            {
                ExpressionMonitor.Trace(start, reportRpcID, e);
                ExpressionMonitor.MointorExecuteTotal();
                if (e == null)
                {
                    ExpressionMonitor.MointorExecuteSuccessTPS();
                    ExpressionMonitor.MointorExecuteSuccessDuration((DateTime.Now - start).TotalMilliseconds);
                }
                else
                {
                    using (var client = new LogLocalClient())
                    {
                        client.SendLogs(new ILog[] { dataChangeLog });
                    }
                    ExpressionMonitor.MointorExecuteFailTPS();
                }

                RpcContext.Current.ResetRpcID(rpcID);
            }
        }
        /// <summary>
        /// DQ执行表达式
        /// </summary>
        /// <returns></returns>
        public ExprResult DQExecute(string jsString, Dictionary<string, object> inputParam)
        {
            var dic = new Dictionary<string, object>();
            dic["InputParam"] = inputParam;
            return JSExecute(jsString, dic);
        }

        #endregion
        #region 高级查询结构表达式

        /// <summary>
        /// 执行高级查询表达式
        /// </summary>
        /// <returns></returns>
        public ExprResult GroupExecute(string exprGroupString, Dictionary<string, object> inputParam)
        {
            ExprResult exprResult = new ExprResult();
            try
            {
                Group exprGroup = JsonConvert.DeserializeObject<Group>(exprGroupString);
                string Expr = GetGroupExpr(exprGroup);
                return JSExecute(Expr, inputParam);
            }
            catch (Exception ex)
            {
                exprResult.State = ResultState.Fail;
                exprResult.ErrMsg = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_2087116524", "表达式:{0}转换高级查询失败：{1}", exprGroupString, ex)}";
                Base.Common.LogUtil.Log(exprResult.ErrMsg, "ExprError");
                return exprResult;
            }
        }
        /// <summary>
        /// 执行高级查询表达式
        /// </summary>
        /// <returns></returns>
        public ExprResult WFExecute(string exprGroupString, FASContext fASContext, Dictionary<string, object> inputParam)
        {
            ExprResult exprResult = new ExprResult();
            string wfExpr = string.Empty;
            try
            {
                inputParam["FASContext"] = fASContext;
                Group exprGroup = JsonConvert.DeserializeObject<Group>(exprGroupString);
                wfExpr = GetGroupExpr(exprGroup);
                var result = JSExecute(wfExpr, inputParam);
                if (result.State == ResultState.Fail)
                {
                    throw new FasException(ExprExceptionCode.ErrorExpr, $"WFExpr执行失败, 转换后脚本内容:{wfExpr}，错误信息{result.ErrMsg}");
                }
                return result;
            }
            catch (Exception ex)
            {
                exprResult.State = ResultState.Fail;
                exprResult.ErrMsg = $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_2087116524", "表达式:{0}转换高级查询失败：{1}\r\n errmsg:{2}", exprGroupString, ex, ex.Message)}";
                Base.Common.LogUtil.Log(exprResult.ErrMsg, "ExprError");
                return exprResult;
            }
        }

        /// <summary>
        /// 根据高级查询获取可执行表达式
        /// </summary>
        /// <param name = "group"></param>
        /// <returns></returns>
        private string GetGroupExpr(Group group)
        {
            if (group == null)
                return null;
            StringBuilder sb = new StringBuilder();
            if (group.Filters != null && group.Filters.Count > 0)
            {
                foreach (var item in group.Filters)
                {
                    if (item is Filter filter)
                    {
                        sb.Append($" {FilterToJS(filter)} ");
                    }
                    else if (item is FRelation relation)
                    {
                        sb.Append($" {RelationToJS(relation.Relation)} ");
                    }
                    else if (item is Group childGroup)
                    {
                        sb.Append($" ({GetGroupExpr(childGroup)}) ");
                    }
                }
            }

            return sb.ToString();
        }

        /// <summary>
        /// 将Relation转换为js
        /// </summary>
        /// <param name = "filter"></param>
        /// <returns></returns>
        private string RelationToJS(string relation)
        {
            switch (relation)
            {
                case "and":
                    return "&&";
                case "or":
                    return "||";
                default:
                    throw new FasException(ExprExceptionCode.NotSupported, "Unsupported condition " + relation);
            }
        }

        /// <summary>
        /// 将Filter转换为js
        /// </summary>
        /// <param name = "filter"></param>
        /// <returns></returns>
        private string FilterToJS(Filter filter)
        {
            var sql = string.Empty;
            var cond = filter.Condition.ToLower();
            string value1 = filter.Value[0];
            string value2 = "";
            DateTime dt;
            DateTime dt2 = DateTime.Now;
            bool isConvert = DateTime.TryParse(value1, out dt);
            bool isConvert2 = false;
            if (filter.Value.Count > 1)
            {
                value2 = filter.Value[1];
                isConvert2 = DateTime.TryParse(value2, out dt2);
            }
            switch (filter.DataType)
            {
                case "Date":
                    if (isConvert)
                    {
                        filter.Code = $"Funcs.TryFormatDateTime({filter.Code},'yyyy-MM-dd')";
                        value1 = $"Funcs.TryFormatDateTime('{value1}','yyyy-MM-dd')";
                    }
                    if (isConvert2)
                    {
                        value1 = $"Funcs.TryFormatDateTime('{value2}','yyyy-MM-dd')";
                    }
                    break;
                case "DateTime":
                    if (isConvert)
                    {
                        filter.Code = $"Funcs.TryFormatDateTime({filter.Code},'yyyy-MM-dd HH:mm:ss')";
                        value1 = $"Funcs.FormatDateTime('{value1}','yyyy-MM-dd HH:mm:ss')";
                    }
                    if (isConvert2)
                    {
                        value2 = $"Funcs.FormatDateTime('{value2}','yyyy-MM-dd HH:mm:ss')";
                    }
                    break;
                case "Boolean":
                    filter.Code = $"Funcs.TryBoolean(String({filter.Code}))";
                    value1 = $"Funcs.TryBoolean(String({value1}))";
                    break;
                case "Time":
                    if (isConvert)
                    {
                        value1 = $"\"{dt.ToString("HH:mm:ss") }\"";
                    }
                    if (isConvert2)
                    {
                        value2 = $"\"{dt2.ToString("HH:mm:ss") }\"";
                    }
                    break;
                default:
                    if (value1.GetType().Name == "String")
                    {
                        value1 = $"\"{value1}\"";
                    }
                    if (value2.GetType().Name == "String")
                    {
                        value2 = $"\"{value2}\"";
                    }
                    break;
            }
            switch (cond)
            {
                case QueryOperator.Equal:
                    sql = $"({filter.Code} == {value1})";
                    break;
                case QueryOperator.NotEqual:
                    sql = $"({filter.Code} != {value1})";
                    break;
                case QueryOperator.LessThan:
                    sql = $"({filter.Code} < {value1})";
                    break;
                case QueryOperator.GreaterThan:
                    sql = $"({filter.Code} > {value1})";
                    break;
                case QueryOperator.GreaterEqualThan:
                    sql = $"({filter.Code} >= {value1})";
                    break;
                case QueryOperator.LessEqualThan:
                    sql = $"({filter.Code} <= {value1})";
                    break;
                case QueryOperator.Contains:
                    sql = $"(({filter.Code}+'').indexOf({value1}) != -1)";
                    break;
                case QueryOperator.NotContains:
                    sql = $"(({filter.Code}+'').indexOf({value1}) == -1)";
                    break;
                case QueryOperator.StartsWith:
                    sql = $"(({filter.Code}+'').startsWith({value1}))";
                    break;
                case QueryOperator.EndsWith:
                    sql = $"(({filter.Code}+'').endsWith({value1}))";
                    break;
                case QueryOperator.Between:
                    if (filter.Value.Count == 1)
                        sql = $"({filter.Code} {QueryOperator.GreaterEqualThan} {value1})";
                    else if (filter.Value.Count == 2)
                        sql = $"({filter.Code} {QueryOperator.GreaterEqualThan} {value1} && {filter.Code} {QueryOperator.LessEqualThan} {value2})";
                    break;
                case QueryOperator.In:
                    sql = $"({value1}.split(',').includes({filter.Code}))";
                    break;
                case QueryOperator.NotIn:
                    sql = $"!({value1}.split(',').includes({filter.Code}))";
                    break;
                default:
                    break;
            }

            return sql;
        }

        #endregion
        #region 表达式调试1.0
        /// <summary>
        /// 执行JS脚本
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, object> DebugExecute(string jsString, Dictionary<string, object> inputParam)
        {
            Dictionary<string, object> exprResult = new Dictionary<string, object>();
            try
            {
                Engine engine = InitEngine(inputParam);
                debugLog = new List<DebugLog>();
                engine.SetValue("Debug", new DebugExecutor());
                object result = engine.Evaluate(jsString).ToObject();
                exprResult["DebugLog"] = debugLog;
                exprResult["State"] = ResultState.Success;
                exprResult["Result"] = result;
                return exprResult;
            }
            catch (JavaScriptException ex)
            {
                exprResult["DebugLog"] = debugLog;
                exprResult["RowNum"] = ex.Location.Start.Line;
                exprResult["State"] = ResultState.Fail;
                exprResult["ErrMsg"] = ex.ToString();
                return exprResult;
            }
            catch (Exception ex)
            {
                exprResult["DebugLog"] = debugLog;
                exprResult["State"] = ResultState.Fail;
                exprResult["ErrMsg"] = ex.ToString();
                return exprResult;
            }
        }

        #endregion
        #region 表达式调试2.0
        /// <summary>
        /// 继续调试 F11 Into F5 Out
        /// </summary>
        /// <param name = "sessionID"></param>
        /// <param name = "stepMode"></param>
        public void ContinueDebug(string sessionID, StepMode stepMode)
        {
            DebugInfo debugInfo = DebugCache.GetInstance().GetDebugCache(sessionID);
            debugInfo.IsContinue = true;
            debugInfo.StepMode = stepMode;
            DebugCache.GetInstance().SetDebugCache(sessionID, debugInfo);
        }

        /// <summary>
        /// 停止调试
        /// </summary>
        /// <param name = "sessionID"></param>
        public void StopDebug(string sessionID)
        {
            DebugCache.GetInstance().RemoveDebugCache(sessionID);
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name = "sessionID"></param>
        /// <returns></returns>
        public DebugInfo GetDebugInfo(string sessionID)
        {
            return DebugCache.GetInstance().GetDebugCache(sessionID);
        }

        /// <summary>
        /// 执行JS脚本
        /// </summary>
        /// <returns></returns>
        public void DebugExpr(string jsString, Dictionary<string, object> inputParam, string sessionID)
        {
            Task.Run(() =>
            {
                try
                {
                    requestID = sessionID;
                    Options options = new Options();
                    options.AllowClr();
                    options.DebugMode(true);
                    Engine engine = new Engine(options);
                    Hashtable hashTable = T.ServiceComponent.Session.Service.AppContext.Current.Session;
                    Dictionary<string, string> dic = new Dictionary<string, string>();
                    DebugCache.GetInstance().SetDebugCache(requestID, new DebugInfo { requestID = sessionID, IsContinue = true, StepMode = StepMode.Into });
                    if (hashTable != null)
                    {
                        foreach (var item in hashTable.Keys)
                        {
                            dic[Convert.ToString(item)] = Convert.ToString(hashTable[item]);
                        }

                        engine.SetValue("Session", dic);
                    }
                    else
                    {
                        dic["UserId"] = "T";
                        dic["UserName"] = "T";
                        engine.SetValue("Session", dic);
                    }

                    if (!executors.Contains("Session"))
                    {
                        executors.Add("Session");
                    }

                    Dictionary<string, IDynamicActionAdapter> dynamicActionAdapters = AdapterCache.GetInstance().GetIDynamicActionAdapters();
                    foreach (var item in dynamicActionAdapters)
                    {
                        if (!executors.Contains(item.Key))
                        {
                            executors.Add(item.Key);
                        }

                        engine.SetValue(item.Key, item.Value);
                    }

                    foreach (var item in inputParam)
                    {
                        engine.SetValue(item.Key, inputParam[item.Key]);
                    }

                    engine.Debugger.Step += DebugHandler_Step;
                    object result = engine.Evaluate(jsString).ToObject();
                    DebugInfo debugInfo = DebugCache.GetInstance().GetDebugCache(sessionID);
                    debugInfo.IsContinue = false;
                    debugInfo.StepMode = StepMode.Out;
                    debugInfo.State = ResultState.Success;
                    debugInfo.Result = result;
                    DebugCache.GetInstance().SetDebugCache(sessionID, debugInfo);
                }
                catch (JavaScriptException ex)
                {
                    DebugInfo debugInfo = DebugCache.GetInstance().GetDebugCache(sessionID);
                    debugInfo.IsContinue = false;
                    debugInfo.StepMode = StepMode.Out;
                    debugInfo.State = ResultState.Fail;
                    debugInfo.ErrMsg = ex.ToString();
                    DebugCache.GetInstance().SetDebugCache(sessionID, debugInfo);
                }
                catch (Exception ex)
                {
                    DebugInfo debugInfo = DebugCache.GetInstance().GetDebugCache(sessionID);
                    debugInfo.IsContinue = false;
                    debugInfo.StepMode = StepMode.Out;
                    debugInfo.State = ResultState.Fail;
                    debugInfo.ErrMsg = ex.ToString();
                    DebugCache.GetInstance().SetDebugCache(sessionID, debugInfo);
                }
                finally
                {
                    Thread.Sleep(1000);
                    DebugCache.GetInstance().RemoveDebugCache(sessionID);
                }
            }

            );
        }

        private static StepMode DebugHandler_Step(object sender, DebugInformation info)
        {
            DebugInfo debugInfo = DebugCache.GetInstance().GetDebugCache(requestID);
            if (debugInfo == null)
            {
                return StepMode.Out;
            }

            foreach (var item in info.CurrentScopeChain)
            {
                var obj = item.GetBindingValue("globalThis").ToObject();
                var values = (obj as IEnumerable<KeyValuePair<string, object>>).Where(t => !executors.Contains(t.Key)).ToList();
                debugInfo.Line = info.Location.Start.Line;
                debugInfo.Column = info.Location.Start.Column;
                debugInfo.NodeType = info.CurrentNode.Type.ToString();
                if (info.CurrentNode.Type == NodeType.DebuggerStatement)
                {
                    debugInfo.IsContinue = false;
                }

                debugInfo.DebugContent = values;
            }

            DebugCache.GetInstance().SetDebugCache(requestID, debugInfo);
            while (!debugInfo.IsContinue)
            {
                Thread.Sleep(10);
            }

            Thread.Sleep(10);
            if (debugInfo.StepMode == StepMode.Into)
            {
                debugInfo.IsContinue = false;
                return StepMode.Into;
            }
            else
            {
                debugInfo.IsContinue = true;
                return StepMode.Out;
            }
        }
        #endregion
    }
}